package org.wx.zk.unconf;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.CountDownLatch;

/**
 * @description: 统一配置 watch 回调
 * @author: wangxun
 * @createDate: 2021/3/23
 * @version: 1.0
 */
@Data
@Slf4j
public class UnConfWatcher implements Watcher, AsyncCallback.StatCallback, AsyncCallback.DataCallback {
    /**
     * zk client
     */
    ZooKeeper zk;
    /**
     * redis 配置信息
     */
    RedisConf redisConf;
    /**
     * 监控的节点
     */
    String watchPath;
    /**
     * 门栓
     */
    CountDownLatch countDownLatch;

    /**
     * 判断节点是不是存在，注册监控事件
     */
    public void  await(){
        log.info("UnConfWatcher 判断是不是存在数据节点");
        zk.exists(watchPath,this,this,"exist node");
        try {
            log.info("开始阻塞，一直到状态发生变更");
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * 节点状态发生变更后，zk server 会自动触发事件
     * @param event
     */
    @Override
    public void process(WatchedEvent event) {
        // 节点的事件
        final Event.EventType type = event.getType();
        switch (type) {
            case None:
                break;
            case NodeCreated:
                // 节点创建
                log.info("节点创建");

                zk.getData(watchPath,this,  this,"NodeCreated");
                break;
            case NodeDeleted:
                // 节点删除
                // 配置信息已经被删除了，需要清空配置，重新设置门栓，等待信息的信息同步
                log.info("节点删除");
                redisConf.setConf("");
                countDownLatch = new CountDownLatch(1);
                break;
            case NodeDataChanged:
                // 节点数据改变
                log.info("节点数据改变");
                zk.getData(watchPath,this,  this,"NodeDataChanged");
                break;
            case NodeChildrenChanged:
                // 子节点改变
                break;
            case DataWatchRemoved:

                break;
            case ChildWatchRemoved:
                break;
            default:
                break;
        }

    }

    /**
     * exist 的回调
     * @param rc
     * @param path
     * @param ctx
     * @param stat
     */
    @Override
    public void processResult(int rc, String path, Object ctx, Stat stat) {
        // 证明有配置信息
        if(null != stat){
            log.info("存在配置信息，开始获取配置");
            zk.getData(watchPath,this,  this,"getConf");
        }
    }

    /**
     * getData 的回调
     * @param rc
     * @param path
     * @param ctx
     * @param data
     * @param stat
     */
    @Override
    public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
        if(null != data){
            // 将配置信息保存在配置对象中
            final String conf = new String(data);
            log.info("获取到配置：{}", conf);
            redisConf.setConf(conf);
            // 获取到配置信息，不进行阻塞了
            countDownLatch.countDown();
        }
    }
}
